<template>
  <li>
    <div
        :class="['tree-node', { expanded: isExpanded(node.id) }]"
        :style="{ paddingLeft: `${level * 20}px` }"
    >
      <span v-if="node.children" :class="{ rotated: isExpanded(node.id) }" class="arrow">▸</span>
      <span class="node-label" @click="handleLabelClick(node)">
        {{ node.label }}
      </span>
    </div>
    <transition name="slide" @after-enter="onAfterEnter" @after-leave="onAfterLeave">
      <ul v-if="isExpanded(node.id) && node.children && node.children.length">
        <tree-node
            v-for="child in node.children"
            :key="child.id"
            :expanded-nodes="expandedNodes"
            :level="level + 1"
            :node="child"
            :parent-labels="[...parentLabels, node.label]"
            @toggle-node="toggleNode"
            @transmit-selection="transmitSelection"
        />
      </ul>
    </transition>
  </li>
</template>

<script lang="ts" setup>
import {defineEmits, defineProps, ref} from 'vue';

interface Node {
  id: string;
  label: string;
  children?: Node[];
}

const props = defineProps<{
  node: Node;
  expandedNodes: Record<string, boolean>;
  level: number;
  parentLabels: string[];
}>();

const emit = defineEmits<{
  (e: 'toggle-node', id: string): void;
  (e: 'transmit-selection', selection: { labels: string[], ids: string[] }): void;
}>();

const toggleNode = (id: string) => {
  emit('toggle-node', id);
};

const isExpanded = (id: string) => {
  return props.expandedNodes[id];
};

// 递归收集节点及其所有子节点的 id
const collectIds = (node: Node): string[] => {
  let ids = [node.id];
  if (node.children && node.children.length > 0) {
    for (const child of node.children) {
      ids = ids.concat(collectIds(child));
    }
  }
  return ids;
};

const selectNode = (node: Node) => {
  const labels = [...props.parentLabels, node.label]; // 收集 label 序列
  const ids = collectIds(node); // 收集被点击节点及其子节点的 id
  emit('transmit-selection', {labels, ids});
};

// 用于记录在节点展开完成后需要选择的节点
const pendingSelection = ref<Node | null>(null);

const handleLabelClick = (node: Node) => {
  if (node.children && node.children.length > 0) {
    // 仅当节点有子节点时才执行展开/收起
    pendingSelection.value = node;
    // 先展开节点
    toggleNode(node.id);
  } else {
    // 如果节点没有子节点，直接选择
    selectNode(node);
  }
};

// 在过渡完成后再调用 selectNode
const onAfterEnter = () => {
  if (pendingSelection.value) {
    selectNode(pendingSelection.value);
    pendingSelection.value = null;
  }
};

// 清除 pendingSelection 以防止在过渡离开时调用 selectNode
const onAfterLeave = () => {
  pendingSelection.value = null;
};

const transmitSelection = (selection: { labels: string[], ids: string[] }) => {
  emit('transmit-selection', selection);
};
</script>

<style scoped>
.tree-node {
  cursor: pointer;
  padding: 5px;
  margin: 5px 0;
  display: flex;
  align-items: center;
  transition: background-color 0.3s ease, color 0.3s ease;
}

.tree-node:hover .node-label {
  background-color: rgb(242, 107, 47);
  color: white;
  border-radius: 4px;
  transition: background-color 0.3s ease, color 0.3s ease;
}

.arrow {
  display: inline-block;
  transition: transform 0.3s ease;
  margin-right: 5px;
}

.arrow.rotated {
  transform: rotate(90deg);
}

.node-label {
  padding: 5px;
  border-radius: 4px;
}

/* Slide Transition Styles */
.slide-enter-active, .slide-leave-active {
  transition: all 0.3s ease;
}

.slide-enter-from {
  max-height: 0;
  opacity: 0;
  transform: scaleY(0);
}

.slide-enter-to {
  max-height: 1000px; /* 足够大的值以容纳内容 */
  opacity: 1;
  transform: scaleY(1);
}

.slide-leave-from {
  max-height: 1000px;
  opacity: 1;
  transform: scaleY(1);
}

.slide-leave-to {
  max-height: 0;
  opacity: 0;
  transform: scaleY(0);
}

.slide-enter-active, .slide-leave-active {
  overflow: hidden;
  transform-origin: top;
}
</style>
